using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Domain.Misc;

namespace Domain.Misc
{
    internal static class IndexedTools
    {
        public static short NextIndex<T>(IList<T> indexedList) where T : IIndexed
        {
            short index = 0;
            foreach (T indexed in indexedList)
            {
                if (indexed.Index > index)
                {
                    index = indexed.Index;
                }
            }
            return index;
        }

        public static T GetAbove<T>(T indexed, IList<T> indexedList) where T : IIndexed
        {
            T above = default(T);
            bool isFirst = true;
            foreach (T potentialAbove in indexedList)
            {
                if ((isFirst || above.Index < potentialAbove.Index)
                    && potentialAbove.Index < indexed.Index)
                {
                    above = potentialAbove;
                    isFirst = false;
                }
            }
            return above;
        }

        public static T GetBelow<T>(T indexed, IList<T> indexedList) where T : IIndexed
        {
            T below = default(T);
            bool isFirst = true;
            foreach (T potentialBelow in indexedList)
            {
                if ((isFirst || potentialBelow.Index < below.Index)
                    && indexed.Index < potentialBelow.Index)
                {
                    below = potentialBelow;
                    isFirst = false;
                }
            }
            return below;
        }

        public static bool MoveUp<T>(T indexed, IList<T> indexedList) where T : IIndexed
        {
            RequireUniqueIndices(indexedList);
            T above = GetAbove(indexed, indexedList);
            if (above != null)
            {
                SwapIndices(above, indexed);
                return true;
            }
            return false;
        }

        public static bool MoveDown<T>(T indexed, IList<T> indexedList) where T : IIndexed
        {
            RequireUniqueIndices(indexedList);
            T below = GetBelow(indexed, indexedList);
            if (below != null)
            {
                SwapIndices(below, indexed);
                return true;
            }
            return false;
        }

        public static void SwapIndices<T>(T thisIndexed, T thatIndexed) where T : IIndexed
        {
            short thisIndex = thisIndexed.Index;
            thisIndexed.Index = thatIndexed.Index;
            thatIndexed.Index = thisIndex;
        }

        public static void Sort<T>(IList<T> indexedList) where T : IIndexed
        {
            ArrayList.Adapter((IList)indexedList).Sort(new IndexedComparer());
        }

        public static bool HaveUniqueIndices<T>(IList<T> indexedList) where T : IIndexed
        {
            List<short> indices = new List<short>();
            foreach (T indexed in indexedList)
            {
                if (indices.Contains(indexed.Index))
                {
                    return false;
                }
                indices.Add(indexed.Index);
            }
            return true;
        }

        public static void ReAssignIndices<T>(IList<T> indexedList) where T : IIndexed
        {
            Sort(indexedList);
            short currentIndex = 1;
            foreach (T indexed in indexedList)
            {
                indexed.Index = currentIndex;
                currentIndex++;
            }
        }

        public static void RequireUniqueIndices<T>(IList<T> indexedList) where T : IIndexed
        {
            if (!HaveUniqueIndices(indexedList))
            {
                ReAssignIndices(indexedList);
            }
        }
    }

    internal class IndexedComparer : IComparer
    {
        public int Compare(object x, object y)
        {
            return ((IIndexed)x).Index.CompareTo(((IIndexed)y).Index);
        }
    }
}
